package org.quartz.impl.rmi;

import org.quartz.TriggerKey;
import org.quartz.impl.jdbcjobstore.*;
import org.quartz.impl.rmi.entity.*;
import org.slf4j.Logger;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;

import static org.quartz.impl.jdbcjobstore.StdJDBCConstants.SELECT_MISFIRED_TRIGGERS;
import static org.quartz.impl.jdbcjobstore.StdJDBCConstants.UPDATE_TRIGGER_STATES_FROM_OTHER_STATES;

/**
 * Created by guowei on 2018/1/13.
 */
public class ServerJDBCDriverDelegate extends UnicastRemoteObject implements AbstractServerDriverDelegate {
    private static final long serialVersionUID = -271947229644133464L;

    private int counter = 0;

    protected Logger logger = null;

    protected String tablePrefix = "QRTZ_";

    protected volatile LinkedList<ProductionRequest> dbWritelists = new LinkedList<>();

    private MutexResource mutex = new MutexResource();

    private Thread thread = new Thread();

    public ServerJDBCDriverDelegate() throws RemoteException{ super(); }

    public static Connection getConn() {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/quartz-test";
        String username = "root";
        String password = "";
        Connection conn = null;
        try {
            Class.forName(driver); //classLoader,加载对应驱动
            conn = (Connection) DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }


    @Override
    public void initialize(Logger logger, String tablePrefix) throws NoSuchDelegateException, RemoteException {
        this.logger = logger;
        this.tablePrefix = tablePrefix;
    }

    @Override
    public int updateTriggerStatesFromOtherStates(AbstractMessage am, ConfigMessage cm) throws SQLException, RemoteException {
        LinkedListEntity lle = new LinkedListEntity(am, cm);
        if (am instanceof UpdateTriggerStatesFromOtherStates) {
            ProductionRequest pr;
            synchronized (dbWritelists) {
                counter++;
                pr = new ProductionRequest(counter, lle);
                dbWritelists.add(pr);
            }
            return (int)notifyDBUtil(pr, am, cm);
        } else {
            return 0;
        }
    }

    @Override
    public List<TriggerKey> selectMisfiredTriggers(AbstractMessage am, ConfigMessage cm) throws SQLException, RemoteException {
        if (am instanceof SelectMisfiredTriggers) {
            return (List<TriggerKey>)notifyDBUtil(null, am, cm);
        }
        return new ArrayList<>();
    }



    //util functions
    private Object notifyDBUtil(ProductionRequest pr, AbstractMessage am, ConfigMessage cm){
        switch (cm.getType()) {
            case "SelectMisfiredTriggers":
                mutex.getRLock();
                DBAccessThread dat = new DBAccessThread(am, rtp(SELECT_MISFIRED_TRIGGERS, cm.getSchedName()),
                        mutex, cm);
                new Thread(dat).start();
                while(dat.result == null){ }
                return dat.result;
            default:
                dbWritelists.add(pr);
                DBWriteThread dwt = new DBWriteThread(rtp(UPDATE_TRIGGER_STATES_FROM_OTHER_STATES,
                        cm.getSchedName()), mutex, dbWritelists);
                if(!this.thread.isAlive()){
                    this.thread = new Thread(dwt);
                    this.thread.start();
                }
                while(dwt.result.get(0).getId() != pr.getId()){ }
                Object execResult = dwt.result.get(0).getResult();
                dwt.result.pop();
                return execResult;
        }
    }

    protected final String rtp(String query, String schemaName) {
        return Util.rtp(query, tablePrefix, schemaName);
    }
}



